﻿using SketchUpAPI.NET.Enums;
using SketchUpAPI.NET.SketchUp.Exception;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace SketchUpAPI.NET.Objects
{
    public class ComponentInstance : DrawingElement
    {
        #region API 函数
        /// <summary>
        /// 设置组件实例的名字
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceSetName(IntPtr instance, [MarshalAs(UnmanagedType.LPUTF8Str)] string name);

        /// <summary>
        /// 获取组件实例的名字
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetName(IntPtr instance, ref IntPtr name);

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceRelease(ref IntPtr instance);

        /// <summary>
        /// 设置Guid
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="guid"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceSetGuid(IntPtr instance, [MarshalAs(UnmanagedType.LPUTF8Str)] string guid);

        /// <summary>
        /// 获取Guid
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="guid"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetGuid(IntPtr instance, ref IntPtr guid);

        /// <summary>
        /// 设置变换
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="transform"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceSetTransform(IntPtr instance, Transformation transform);

        /// <summary>
        /// 获取变换
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="transform"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetTransform(IntPtr instance, ref Transformation transform);

        /// <summary>
        /// 获取组件的定义
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="component"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetDefinition(IntPtr instance, out IntPtr component);

        /// <summary>
        /// 设置是否锁定
        /// </summary>
        /// <param name="instance"></param>
        /// <param name=""></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceSetLocked(IntPtr instance, bool isLock);

        /// <summary>
        /// 获取是否锁定
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="is_locked"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceIsLocked(IntPtr instance, out bool is_locked);

        /// <summary>
        /// 计算体积
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="transform"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceComputeVolume(IntPtr instance, Transformation transform, out double volume);

        /// <summary>
        /// 创建动态组件信息
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="dc_info"><see cref="DynamicComponentInfo"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceCreateDCInfo(IntPtr instance, out IntPtr dc_info);

        /// <summary>
        /// 附属组件个数
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetNumAttachedInstances(IntPtr instance, out int count);

        /// <summary>
        /// 获取全部附属组件
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="len"></param>
        /// <param name="instances"><see cref="ComponentInstance"/>[]</param>
        /// <param name="realcount"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetAttachedInstances(IntPtr instance, int len, IntPtr[] instances, out int realcount);

        /// <summary>
        /// 附属物体个数
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetNumAttachedToDrawingElements(IntPtr instance, out int count);

        /// <summary>
        /// 获取全部附属物体
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="len"></param>
        /// <param name="elements"><see cref="DrawingElement"/></param>
        /// <param name="realcount"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUComponentInstanceGetAttachedToDrawingElements(IntPtr instance, int len, IntPtr[] elements, out int realcount);
        #endregion

        /// <summary>
        /// 组件实例的名字
        /// </summary>
        /// <remarks>实例默认没有名字</remarks>
        public virtual string Name
        {
            get
            {
                StringRef sr = StringRef.Empty;
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetName(Id, ref sr.Id));
                return sr.Dispose();
            }
            set
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceSetName(Id, value));
            }
        }

        /// <summary>
        /// Guid
        /// </summary>
        public virtual string Guid
        {
            get
            {
                StringRef s = StringRef.Empty;
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetGuid(Id, ref s.Id));
                return s.Dispose();
            }
            set
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceSetGuid(Id, value));
            }
        }

        /// <summary>
        /// 变换
        /// </summary>
        public virtual Transformation Transform
        {
            get
            {
                Transformation t = new Transformation();
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetTransform(Id, ref t));
                return t;
            }
            set
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceSetTransform(Id, value));
            }
        }

        /// <summary>
        /// 组件定义
        /// </summary>
        public virtual ComponentDefinition Definition
        {
            get
            {
                ComponentDefinition def = new ComponentDefinition();
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetDefinition(Id, out def.Id));
                return def;
            }
        }

        /// <summary>
        /// 锁定
        /// </summary>
        public bool Locked
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceIsLocked(Id, out bool l));
                return l;
            }
            set
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceSetLocked(Id, value));
            }
        }

        /// <summary>
        /// 体积
        /// </summary>
        /// <remarks>变换后的体积</remarks>
        public double Volume
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceComputeVolume(Id, Transform, out double v));
                return v;
            }
        }

        /// <summary>
        /// 附属组件
        /// </summary>
        public List<ComponentInstance> AttachedInstances
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetNumAttachedInstances(Id, out int count));
                IntPtr[] pts = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetAttachedInstances(Id, count, pts, out _));
                return pts.Select(i => new ComponentInstance(i)).ToList();
            }
        }

        /// <summary>
        /// 附属物体
        /// </summary>
        public List<DrawingElement> AttachedElement
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetNumAttachedToDrawingElements(Id, out int count));
                IntPtr[] pts = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceGetAttachedToDrawingElements(Id, count, pts, out _));
                return pts.Select(i => new DrawingElement(i)).ToList();
            }
        }

        internal ComponentInstance() { }

        internal ComponentInstance(IntPtr id) : base(id) { }

        /// <summary>
        /// 计算再某个变换下的体积
        /// </summary>
        /// <param name="trans"></param>
        /// <returns></returns>
        public double CalculateVolume(Transformation trans)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceComputeVolume(Id, trans, out double v));
            return v;
        }

        /// <summary>
        /// 创建动态组件
        /// </summary>
        /// <returns></returns>
        public DynamicComponentInfo CreateDynamicComponent()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceCreateDCInfo(Id, out IntPtr id));
            return new DynamicComponentInfo(id);
        }

        public override void Dispose()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUComponentInstanceRelease(ref Id));
        }
    }
}